home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 February: Tool Chest / Dev.CD Feb 95 / Dev.CD Feb 95.toast / Tool Chest / Development Tools & Languages / Dylan Related / Mindy-1.1 (sources only) / mindy-1.1 / interp / driver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-18  |  8.3 KB  |  382 lines  |  [TEXT/ttxt]

  1. /**********************************************************************\
  2. *
  3. *  Copyright (c) 1994  Carnegie Mellon University
  4. *  All rights reserved.
  5. *  
  6. *  Use and copying of this software and preparation of derivative
  7. *  works based on this software are permitted, including commercial
  8. *  use, provided that the following conditions are observed:
  9. *  
  10. *  1. This copyright notice must be retained in full on any copies
  11. *     and on appropriate parts of any derivative works.
  12. *  2. Documentation (paper or online) accompanying any system that
  13. *     incorporates this software, or any part of it, must acknowledge
  14. *     the contribution of the Gwydion Project at Carnegie Mellon
  15. *     University.
  16. *  
  17. *  This software is made available "as is".  Neither the authors nor
  18. *  Carnegie Mellon University make any warranty about the software,
  19. *  its performance, or its conformity to any specification.
  20. *  
  21. *  Bug reports, questions, comments, and suggestions should be sent by
  22. *  E-mail to the Internet address "gwydion-bugs@cs.cmu.edu".
  23. *
  24. ***********************************************************************
  25. *
  26. * $Header: driver.c,v 1.15 94/07/26 18:32:10 hallgren Exp $
  27. *
  28. * Main driver routines for mindy.
  29. *
  30. \**********************************************************************/
  31.  
  32. #include <setjmp.h>
  33. #ifdef sgi
  34. #define _BSD_SIGNALS
  35. #endif
  36. #include <signal.h>
  37. #include <string.h>
  38. #include <sys/types.h>
  39. #include <sys/time.h>
  40. #include <sys/errno.h>
  41. #ifdef MACH
  42. extern void bzero(void *ptr, size_t bytes);
  43. extern int select(int nfds, fd_set *readfds, fd_set *write_fds,
  44.           fd_set *except_fds, struct timeval *timeout);
  45. #endif
  46. #if defined(__osf__) || defined(ultrix)
  47. extern void bzero(char *string, int length);
  48. extern int select(int nfds, fd_set *readfds, fd_set *writefds,
  49.           fd_set *exceptfds, struct timeval *timeout);
  50. #include <exc_handling.h>
  51. #endif
  52. #ifdef sgi
  53. #define pause buttplug
  54. #include <unistd.h>
  55. #undef pause
  56. #include <bstring.h>
  57. #include <errno.h>
  58. #endif
  59. #ifdef sparc
  60. extern void bzero(char *string, int length);
  61. extern int select(int nfds, fd_set *readfds, fd_set *writefds,
  62.           fd_set *exceptfds, struct timeval *timeout);
  63. extern int sigpause(int sigmask);
  64. #include <errno.h>
  65. extern int sigvec(int sig, struct sigvec *vec, struct sigvec *ovec);
  66. #endif
  67.  
  68. #include "mindy.h"
  69. #include "gc.h"
  70. #include "thread.h"
  71. #include "driver.h"
  72. #include "bool.h"
  73. #include "gc.h"
  74. #if SLOW_FUNCTION_POINTERS
  75. #include "interp.h"
  76. #endif
  77.  
  78. static boolean InInterpreter = FALSE;
  79. static jmp_buf Catcher;
  80. static enum pause_reason PauseReason;
  81.  
  82. #define OPS_PER_TIME_SLICE 100
  83.  
  84.  
  85. /* SIGINT handling. */
  86.  
  87. static void (*InterruptHandler)(void) = NULL;
  88. static boolean InterruptPending = FALSE;
  89.  
  90. static void sigint_handler()
  91. {
  92.     if (InterruptHandler)
  93.     InterruptHandler();
  94.     else
  95.     InterruptPending = TRUE;
  96. }
  97.  
  98. void set_interrupt_handler(void (*handler)(void))
  99. {
  100.     InterruptHandler = handler;
  101.     if (InterruptPending) {
  102.     InterruptPending = FALSE;
  103.     handler();
  104.     }
  105. }
  106.  
  107. void clear_interrupt_handler(void)
  108. {
  109.     InterruptHandler = NULL;
  110. }
  111.  
  112.  
  113. /* Waiting on file descriptors. */
  114.  
  115. static struct waiters {
  116.     fd_set fds;
  117.     obj_t events[FD_SETSIZE];
  118. } Readers, Writers;
  119. static int NumFds;
  120.  
  121. static void check_fds(boolean block)
  122. {
  123.     fd_set readfds, writefds;
  124.     int nfound, fd;
  125.     struct timeval tv, *tvp;
  126.  
  127.     if (NumFds == 0) {
  128.     if (block)
  129.         sigpause(0);
  130.     return;
  131.     }
  132.  
  133.     memcpy(&readfds, &Readers.fds, sizeof(readfds));
  134.     memcpy(&writefds, &Writers.fds, sizeof(writefds));
  135.  
  136.     if (block)
  137.     tvp = NULL;
  138.     else {
  139.     tv.tv_usec = 0;
  140.     tv.tv_sec = 0;
  141.     tvp = &tv;
  142.     }
  143.  
  144. #ifdef hpux
  145.     nfound = select(NumFds, (int *)&readfds, (int *)&writefds, NULL, tvp);
  146. #else
  147.     nfound = select(NumFds, &readfds, &writefds, NULL, tvp);
  148. #endif
  149.  
  150.     if (nfound < 0) {
  151.     switch (errno) {
  152.       case EBADF:
  153.         /* One of the file descriptors when bad.  Wake everyone up */
  154.         /* and let the individual threads figure out who is selecting */
  155.         /* on a bogus fd. */
  156.         for (fd = 0; fd < NumFds; fd++) {
  157.         if (FD_ISSET(fd, &Readers.fds))
  158.             event_broadcast(Readers.events[fd]);
  159.         if (FD_ISSET(fd, &Writers.fds))
  160.             event_broadcast(Writers.events[fd]);
  161.         }
  162.         FD_ZERO(&Readers.fds);
  163.         FD_ZERO(&Writers.fds);
  164.         NumFds = 0;
  165.         break;
  166.         
  167.       case EINTR:
  168.         break;
  169.       case EINVAL:
  170.         lose("select failed with EINVAL?");
  171.     }
  172.     }
  173.     else if (nfound > 0) {
  174.     for (fd = 0; fd < NumFds; fd++) {
  175.         if (FD_ISSET(fd, &readfds)) {
  176.         event_broadcast(Readers.events[fd]);
  177.         FD_CLR(fd, &Readers.fds);
  178.         }
  179.         if (FD_ISSET(fd, &writefds)) {
  180.         event_broadcast(Writers.events[fd]);
  181.         FD_CLR(fd, &Writers.fds);
  182.         }
  183.     }
  184.     for (fd = NumFds - 1; fd >= 0; fd--)
  185.         if (FD_ISSET(fd, &Readers.fds) || FD_ISSET(fd, &Writers.fds))
  186.         break;
  187.     NumFds = fd+1;
  188.     }
  189. }
  190.  
  191. static void wait_for_fd(struct thread *thread, int fd, struct waiters *waiters,
  192.             void (*advance)(struct thread *thread))
  193. {
  194.     obj_t event;
  195.  
  196.     FD_SET(fd, &waiters->fds);
  197.  
  198.     if (NumFds <= fd)
  199.     NumFds = fd+1;
  200.  
  201.     event = waiters->events[fd];
  202.     if (event == obj_False) {
  203.     event = make_event();
  204.     waiters->events[fd] = event;
  205.     }
  206.  
  207.     event_wait(thread, event, obj_False, advance);
  208. }
  209.  
  210. void wait_for_input(struct thread *thread, int fd,
  211.             void (*advance)(struct thread *thread))
  212. {
  213.     wait_for_fd(thread, fd, &Readers, advance);
  214. }
  215.  
  216. void wait_for_output(struct thread *thread, int fd,
  217.              void (*advance)(struct thread *thread))
  218. {
  219.     wait_for_fd(thread, fd, &Writers, advance);
  220. }
  221.  
  222.  
  223.  
  224. /* Driver loop entry points. */
  225.  
  226. static void set_pause_interrupted(void)
  227. {
  228.     PauseReason = pause_Interrupted;
  229. }
  230.  
  231. enum pause_reason do_stuff(void)
  232. {
  233.     struct thread *thread;
  234.     volatile int timer;
  235.     volatile boolean do_select = TRUE;
  236.  
  237.     assert (!InInterpreter);
  238.  
  239.     do {
  240.     if (do_select)
  241.         check_fds(FALSE);
  242.     else
  243.         do_select = TRUE;
  244.     PauseReason = pause_NoReason;
  245.     thread = thread_pick_next();
  246.     if (thread) {
  247.         timer = OPS_PER_TIME_SLICE;
  248.         InInterpreter = TRUE;
  249.         set_interrupt_handler(set_pause_interrupted);
  250.         _setjmp(Catcher);
  251.         if (PauseReason == pause_NoReason)
  252.         while (timer-- > 0) {
  253. #if SLOW_FUNCTION_POINTERS
  254.             if (thread->advance)
  255.             thread->advance(thread);
  256.             else
  257.             interpret_next_byte(thread);
  258. #else
  259.             thread->advance(thread);
  260. #endif
  261.         }
  262.         InInterpreter = FALSE;
  263.         clear_interrupt_handler();
  264.  
  265.         if (TimeToGC)
  266.         collect_garbage();
  267.     }
  268.     else if (all_threads() == NULL)
  269.         PauseReason = pause_NothingToRun;
  270.     else {
  271.         set_interrupt_handler(set_pause_interrupted);
  272.         check_fds(TRUE);
  273.         do_select = FALSE;
  274.         clear_interrupt_handler();
  275.     }
  276.     } while (PauseReason == pause_NoReason
  277.          || PauseReason == pause_PickNewThread);
  278.     return PauseReason;
  279. }
  280.  
  281. enum pause_reason single_step(struct thread *thread)
  282. {
  283.     assert(!InInterpreter);
  284.     assert(thread->status == status_Running);
  285.     assert(thread->suspend_count == 0);
  286.  
  287.     check_fds(FALSE);
  288.  
  289.     thread_set_current(thread);
  290.     InInterpreter = TRUE;
  291.     PauseReason = pause_NoReason;
  292.     set_interrupt_handler(set_pause_interrupted);
  293.     if (_setjmp(Catcher) == 0) {
  294. #if SLOW_FUNCTION_POINTERS
  295.     if (thread->advance)
  296.         thread->advance(thread);
  297.     else
  298.         interpret_next_byte(thread);
  299. #else
  300.     thread->advance(thread);
  301. #endif
  302.     }
  303.     InInterpreter = FALSE;
  304.     clear_interrupt_handler();
  305.     if (TimeToGC)
  306.     collect_garbage();
  307.     return PauseReason;
  308. }
  309.  
  310. void go_on(void)
  311. {
  312.     assert(InInterpreter);
  313.     _longjmp(Catcher, 1);
  314. }
  315.  
  316. void pause(enum pause_reason reason)
  317. {
  318.     clear_interrupt_handler();
  319.     if (reason != pause_NoReason)
  320.     PauseReason = reason;
  321.     go_on();
  322. }
  323.  
  324.  
  325. /* GC stuff. */
  326.  
  327. static void scav_waiters(struct waiters *waiters)
  328. {
  329.     int fd;
  330.  
  331.     for (fd = 0; fd < FD_SETSIZE; fd++)
  332.     scavenge(waiters->events + fd);
  333. }
  334.  
  335. void scavenge_driver_roots(void)
  336. {
  337.     scav_waiters(&Readers);
  338.     scav_waiters(&Writers);
  339. }
  340.  
  341.  
  342. /* Init stuff. */
  343.  
  344. static void init_waiters(struct waiters *waiters)
  345. {
  346.     int fd;
  347.  
  348.     FD_ZERO(&waiters->fds);
  349.     for (fd = 0; fd < FD_SETSIZE; fd++)
  350.     waiters->events[fd] = obj_False;
  351. }
  352.  
  353. void init_driver()
  354. {
  355. #ifdef linux
  356.     struct sigaction sa;
  357. #else
  358.     struct sigvec sv;
  359. #endif
  360.  
  361.     init_waiters(&Readers);
  362.     init_waiters(&Writers);
  363.     NumFds = 0;
  364.  
  365. #ifdef linux
  366.     sa.sa_handler = sigint_handler;
  367.     sa.sa_mask = 0;
  368.     sa.sa_flags = 0;
  369.     sa.sa_restorer = NULL;
  370.     sigaction(SIGINT, &sa, NULL);
  371. #else
  372.     sv.sv_handler = sigint_handler;
  373.     sv.sv_mask = 0;
  374.     sv.sv_flags = 0;
  375. #ifdef hpux
  376.     sigvector(SIGINT, &sv, NULL);
  377. #else
  378.     sigvec(SIGINT, &sv, NULL);
  379. #endif
  380. #endif
  381. }
  382.